
#include "Punkt.h"


#include "Wektor.h"

#include "WekNormalne.h"
#include "ZapiszPlik.h"
#include <fstream>
#include <iostream>
#include <math.h>
#include <cstdlib>
#include <climits>

using namespace std;

void histogram(double**, int, int);

/**
 * oblicza wektory normalne dla kolejnych pomiarów.
 */
void WekNormalne::liczWektoryNormalne(Skan3D* skan3d) {
    //tymczasowe ograniczenie bo się wysypuje ;(
    //skan3d->maxW = 2000;
    int D = 2;
    for (int I = D; I < skan3d->maxW - D; I++) {
        for (int J = D; J < skan3d->maxK - D; J++) {
            WekNormalne::liczNormalny(skan3d->punkt[I][J],
                    skan3d->punkt[I + D][J],
                    skan3d->punkt[I][J + D],
                    skan3d->punkt[I - D][J],
                    skan3d->punkt[I][J - D]
                    );

            WekNormalne::liczKolor(skan3d->punkt[I][J]);
        }
        //std::cout<<"I: "<<I<<std::endl;
    }
}

/**
 * oblicza wektory normalne dla kolejnych pomiarów.
 */
void WekNormalne::liczWektoryNormalne2(Skan3D* skan3d, double min, double max, double maxR = 7.0) {


    cout << "cosinusy" << endl;
    double** tabCosPoz = new double* [skan3d->maxW];
    for (int i = 0; i < skan3d->maxW; i++) tabCosPoz[i] = new double [skan3d->maxK];

    double** tabCosPio = new double* [skan3d->maxW];
    for (int i = 0; i < skan3d->maxW; i++) tabCosPio[i] = new double [skan3d->maxK];

    int D = 1;
    for (int I = D; I < skan3d->maxW - D; I++) {
        for (int J = D; J < skan3d->maxK - D; J++) {

            Punkt* pP = &(skan3d->punkt[I][J]);

            if (pP->r > maxR) {
                pP->Obszar = -2;
                continue;
            }

            Punkt pA, pB, pC, pD;
            bool ok = true;

            //dla punktu A:
            bool czyMinA = false;
            for (int ij = D; ij < skan3d->maxW - D - I; ij++) {
                double odl = pP->odleglosc(skan3d->punkt[I + ij][J]);
                if (odl > max) {
                    ok = false;
                    break;
                }
                if (odl > min) {
                    pA = skan3d->punkt[I + ij][J];
                    czyMinA = true;
                    break;
                }
                //cout<<"A: ("<<I<<"; "<<J<<") "<<ij<<endl;
            }
            //dla punktu B:
            bool czyMinB = false;
            for (int ij = D; ij < skan3d->maxK - D - J; ij++) {
                double odl = pP->odleglosc(skan3d->punkt[I][J + ij]);
                if (odl > max) {
                    ok = false;
                    break;
                }
                if (odl > min) {
                    pB = skan3d->punkt[I][J + ij];
                    czyMinB = true;
                    break;
                }
                //cout<<"B: "<<ij<<endl;
            }
            //dla punktu C:
            bool czyMinC = false;
            for (int ij = D; ij < I; ij++) {
                double odl = pP->odleglosc(skan3d->punkt[I - ij][J]);
                if (odl > max) {
                    ok = false;
                    break;
                }
                if (odl > min) {
                    pC = skan3d->punkt[I - ij][J];
                    czyMinC = true;
                    break;
                }
                //cout<<"C: "<<ij<<endl;
            }
            //dla punktu D:
            bool czyMinD = false;
            for (int ij = D; ij < J; ij++) {
                double odl = pP->odleglosc(skan3d->punkt[I][J - ij]);
                if (odl > max) {
                    ok = false;
                    break;
                }
                if (odl > min) {
                    pD = skan3d->punkt[I][J - ij];
                    czyMinD = true;
                    break;
                }
                //cout<<"D: "<<ij<<endl;
            }
            if (ok && czyMinA && czyMinB && czyMinC && czyMinD) {
                WekNormalne::liczNormalny(*pP, pA, pB, pC, pD);
                WekNormalne::liczKolor(*pP);

                tabCosPoz[I][J] = pP->Vnor.razy(pC.Vnor) * pP->Vnor.razy(pC.Vnor);
                tabCosPio[I][J] = pP->Vnor.razy(pD.Vnor);

            }
        }//J++
    }//I++

    histogram(tabCosPoz, skan3d->maxW, skan3d->maxK);
    ZapiszPlik::zapiszPPM6(tabCosPio, skan3d->maxW, skan3d->maxK, "/home/arkadiusz/Pulpit/testPio.ppm");
    ZapiszPlik::zapiszPPM6(tabCosPoz, skan3d->maxW, skan3d->maxK, "/home/arkadiusz/Pulpit/testPoz.ppm");
}

/**
 * oblicza wektory normalne dla kolejnych pomiarów.
 */
void WekNormalne::liczWektoryNormalne3(Skan3D* skan3d, double min, double max, double maxR = 7.0) {
    //    Matrix<Point> norm;
    //    norm.create(mat.geti(), mat.getj());
    //Matrix<Point> Transform::normalVectors(Matrix<Point> mat, bool only_four, Real dist_min, Real dist_max) {
    //    int maxI = skan3d->maxW;
    //    int maxJ = skan3d->maxK;
    //    for (int i = 0; i < maxI; i++)
    //        for (int j = 0; j < maxJ; j++) {
    //            Wektor a(0, 0, 0);
    //            // różne pary można wybrać:
    //            int pairs[8][2] = {
    //                { 1, 5},
    //                { 5, 7},
    //                { 7, 3},
    //                { 3, 1},
    //                { 0, 8},
    //                { 2, 6},
    //                { 3, 5},
    //                { 1, 7}
    //            };
    //            for (int s = 0; s < 4; s++) {
    //                int dx1 = pairs[s][0] % 3 - 1;
    //                int dy1 = pairs[s][0] / 3 - 1;
    //                int dx2 = pairs[s][1] % 3 - 1;
    //                int dy2 = pairs[s][1] / 3 - 1;
    //
    //                if (((i + dx1) < 0) || ((i + dx1) >= maxI)
    //                        || ((j + dy1) < 0) || ((j + dy1) >= maxJ))
    //                    continue;
    //                if (((i + dx2) < 0) || ((i + dx2) >= maxI)
    //                        || ((j + dy2) < 0) || ((j + dy2) >= maxJ))
    //                    continue;
    //
    //                Wektor pa(skan3d->punkt[i + dx1][j + dy1].x - skan3d->punkt[i][j].x,
    //                        skan3d->punkt[i + dx1][j + dy1].y - skan3d->punkt[i][j].y,
    //                        skan3d->punkt[i + dx1][j + dy1].z - skan3d->punkt[i][j].z
    //                        );
    //                Wektor pb(skan3d->punkt[i + dx2][j + dy2].x - skan3d->punkt[i][j].x,
    //                        skan3d->punkt[i + dx2][j + dy2].y - skan3d->punkt[i][j].y,
    //                        skan3d->punkt[i + dx2][j + dy2].z - skan3d->punkt[i][j].z
    //                        );
    //
    //                if ((pa.dlugosc() < min) || (pa.dlugosc() > max) ||
    //                        (pb.dlugosc() < min) || (pa.dlugosc() > max))
    //                    continue; // wektory za krótkie/za długie
    //
    //                a = a + pa*pb;
    //            }
    //
    //            if (a.dlugosc() > 0)
    //                a.norm();
    //            skan3d->punkt[i][j].Vnor = a;
    //            WekNormalne::liczKolor(skan3d->punkt[i][j]);
    //            //cout << "# d=" << d << "  sum:" << sum << endl;
    //        }

}

/**
 *
 */
void WekNormalne::liczNormalny(Punkt &p, Punkt A, Punkt B, Punkt C, Punkt D) {
    /*
     *       A
     *       |
     *   D - p - B
     *       |
     *       C
     */
    //obliczenie kolejnych wektorów łączących punk p z punkatami A,B,C i D
    Wektor pA(A.x - p.x, A.y - p.y, A.z - p.z);
    Wektor pB(B.x - p.x, B.y - p.y, B.z - p.z);
    Wektor pC(C.x - p.x, C.y - p.y, C.z - p.z);
    Wektor pD(D.x - p.x, D.y - p.y, D.z - p.z);
    //suma iloczynów wektorowych
    //każdy lioczyn daje wektor prostobadły do płaszczyzny iloczynu,
    //suma powinna być równoważna do wek. normalnego.
    Wektor w = (pA * pB) + (pB * pC) + (pC * pD) + (pD * pA);
    //Wektor w = pA; //*pD;// + pC*pB + pD*pC + pA*pD;
    w.norm(); //normowanie
    p.Vnor.x = w.x; //przypisanie wartości
    p.Vnor.y = w.y; //przypisanie wartości
    p.Vnor.z = w.z; //przypisanie wartości
}

/**
 *
 */
void WekNormalne::liczKolor(Punkt & p) {
    /*
    p.k.R = abs((int) (p.Vnor.x * 255.0));
    p.k.G = abs((int) (p.Vnor.y * 255.0));
    p.k.B = abs((int) (p.Vnor.z * 255.0));
     */
    p.k.R = (int) ((p.Vnor.x + 1)* 128.0);
    p.k.G = (int) ((p.Vnor.y + 1)* 128.0);
    p.k.B = (int) ((p.Vnor.z + 1)* 128.0);

}

/**
 *
 */

void WekNormalne::cosinusy(Skan3D* skan3d, int dx, int dy) {
    cout << "cosinusy" << endl;
    double** tabCos = new double* [skan3d->maxW];
    for (int i = 0; i < skan3d->maxW; i++) tabCos[i] = new double [skan3d->maxK];

    for (int w = 0; w < skan3d->maxW - 1; w++) {
        for (int k = 0; k < skan3d->maxK; k++) {
            tabCos[w][k] = skan3d->punkt[w][k].Vnor
                    .razy(skan3d->punkt[w + 1][k].Vnor);
        }
    }

    ZapiszPlik::zapiszPPM6(tabCos, skan3d->maxW, skan3d->maxK, "/home/arkadiusz/Pulpit/test.ppm");

}
//=================================================================================

/**
 *  Histogram
 */
void histogram(double** t, int W, int K) {
    double hist[255];
    for (int i = 0; i < 255; i++) hist[i] = 0;

    for (int w = 2; w < W - 1; w++) {
        for (int k = 1; k < K - 1; k++) {
            int x = int((t[w][k] + 1)*128);

            hist[x]++;
            if (x < 0)
                cout << "(" << w << ";" << k << ") = " << x << endl;
            //cout<<int((t[w][k] + 1)*128) <<endl;
        }
    }

    int MaxWar = 0;
    for (int i = 0; i < 255; i++) {
        //cout << i << ". " << hist[i] << endl;
        if (hist[i] > MaxWar) MaxWar = hist[i];
    }
    //cout << "MaxWAR = " << MaxWar << endl;
    char* nazwaPliku = "/home/arkadiusz/Pulpit/testHist.pbm";
    FILE* f = fopen(nazwaPliku, "w");
    fclose(f);
    fstream plik(nazwaPliku, std::ios::in | std::ios::out);
    if (plik.fail()) { //nie ma pliku
        cout << "Brak Pliku!" << endl;
    }
    //MaxWar = 1000;
    // cout << "zapiszPBM: plik otwarty" << std::endl;
    plik << "P1" << endl;
    plik << MaxWar << " " << 255 << endl;

    //plik.close();
    //plik.open(nazwaPliku, std::ios::app | std::ios::binary);

    for (int I = 0; I < 255; I++) {
        for (int J = 0; J < hist[I]; J++) {
            plik << "1 ";
        }
        for (int J = hist[I]; J < MaxWar; J++) {
            plik << "0 ";
        }
        plik << endl;
    }
    //cout << "zapiszPBM: zapisano P3" << std::endl;

    plik.close();
    //cout << "zapiszPBM: plik zamkniety" << std::endl;


}
